package com.zh.generator.core;


import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.lang.reflect.ActualTypeMapperPool;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.reflect.MethodUtils;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 通用查询
 *
 * @author zhanxf
 * @date 2022/11/10
 */
public class BaseRepository<M extends DefaultMapper<T>, T> extends ServiceImpl<M, T> implements IService<T> {

    public static Map<String, BaseRepository> allRepository;

    public void removeByTid(String tid) {
        remove(new QueryWrapper<T>().eq("tid", tid));
    }

    public <K> void removeByField(SFunction<T, K> field, Object value) {
        remove(new LambdaQueryWrapper<T>().eq(field, value));
    }

    public <K> void count(SFunction<T, K> field, Object value) {
        count(new LambdaQueryWrapper<T>().eq(field, value));
    }

    public <K> List<K> keys(IPage<T> page, SFunction<T, K> keyField) {
        if (page.getRecords() == null || page.getRecords().size() == 0) {
            return Collections.EMPTY_LIST;
        }

        return keys(page.getRecords(), keyField);
    }

    public <K> List<K> keys(List<T> list, SFunction<T, K> keyField) {
        if (list == null || list.size() == 0) {
            return Collections.EMPTY_LIST;
        }

        return list.stream().map(a -> keyField.apply(a)).collect(Collectors.toList());
    }

    public <K> Map<K, List<T>> groupBy(SFunction<T, K> inField, List<K> inList) {
        List<T> list = lambdaQuery().in(inField, inList).list();
        Map<K, List<T>> map = new HashMap<>();
        if (list == null || list.size() == 0) {
            return map;
        }

        list.forEach(a -> {
            K key = inField.apply(a);
            if (!map.containsKey(key)) {
                map.put(key, new ArrayList<>());
            }

            map.get(key).add(a);
        });
        return map;
    }

    public boolean checkUnique(Object id, Pair<String, Object>... pairs) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        for (Pair<String, Object> pair : pairs) {
            queryWrapper.eq(pair.getKey(), pair.getValue());
        }
        //新增
        if (ObjectUtil.isEmpty(id)) {
            return count(queryWrapper) == 0;
        } else {
            //修改
            List<T> list = baseMapper.selectList(queryWrapper);
            if (CollectionUtil.isEmpty(list)) {
                return true;
            } else if (list.size() == 1) {
                T t = list.get(0);
                String tidValue = getValue(t, "getTid");
                if (tidValue.equals(id.toString())) {
                    return true;
                } else {
                    return getValue(t, "getId").equals(id.toString());
                }
            } else {
                return false;
            }
        }
    }

    private String getValue(T t, String methodName) {
        Method idMethod = MethodUtils.getAccessibleMethod(t.getClass(), methodName);
        try {
            Object value = idMethod.invoke(t);
            if (value == null) {
                return "";
            } else {
                return value.toString();
            }
        } catch (Exception e) {
            return "";
        }
    }

    public static BaseRepository getRepository(Class DOClass) {
        if (allRepository == null) {
            allRepository = SpringUtil.getBeansOfType(BaseRepository.class);
        }
        return allRepository.values().stream().filter(a -> {
            Map<String, Type> map1 = ActualTypeMapperPool.getStrKeyMap(a.getClass());
            Class clazz = (Class) map1.get("T");
            return clazz == DOClass;
        }).findFirst().orElse(null);
    }
}

